package com.zenithmind.disk.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.disk.feign.UserFeignClient;
import com.zenithmind.disk.mapper.FilesMapper;
import com.zenithmind.disk.pojo.domain.Files;
import com.zenithmind.disk.pojo.dto.FileDTO;
import com.zenithmind.disk.pojo.vo.FileVO;
import com.zenithmind.disk.pojo.vo.UsersVO;
import com.zenithmind.disk.service.FilesService;
import com.zenithmind.common.result.Result;
import com.zenithmind.common.annotation.DataCache;
import com.zenithmind.common.annotation.DataCacheEvict;
import com.zenithmind.common.constant.CacheConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件服务实现 - 重构版本
 * 遵循单一职责原则：专注于核心文件操作
 * 遵循依赖倒置原则：依赖抽象接口
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements FilesService {
    
    private final UserFeignClient userFeignClient;

    @Value("${file.upload.path}")
    private String uploadPath;
    
    // 缓存前缀常量定义
    private static final String CACHE_FILES_PREFIX = "files";
    private static final String CACHE_USER_FILES_PREFIX = "user:files";

    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_FILES_PREFIX, key = "#result.id")
    public FileVO uploadFile(MultipartFile file, String userId, String parentId) {
        try {
            // 处理root标记
            if ("root".equals(parentId)) {
                parentId = null;
            }
            
            String originalFilename = file.getOriginalFilename();
            long fileSize = file.getSize();
            String fileType = file.getContentType();

            // 检查用户存储空间
            Result<UsersVO> userResult = userFeignClient.getUserById(userId);
            if (userResult == null || !userResult.isSuccess() || userResult.getData() == null) { 
                throw new RuntimeException("获取用户信息失败或用户不存在");
            }
            UsersVO user = userResult.getData();

            if (user.getStorageUsed() + fileSize > user.getStorageLimit()) {
                throw new RuntimeException("存储空间不足");
            }

            // 生成文件MD5码
            String fileMd5 = DigestUtil.md5Hex(file.getInputStream());
            
            // 检查重复文件名
            LambdaQueryWrapper<Files> duplicateCheckWrapper = new LambdaQueryWrapper<>();
            duplicateCheckWrapper.eq(Files::getUserId, userId)
                    .eq(Files::getFileName, originalFilename)
                    .eq(Files::getStatus, 1);
            
            if (parentId == null) {
                duplicateCheckWrapper.isNull(Files::getParentId);
            } else {
                duplicateCheckWrapper.eq(Files::getParentId, parentId);
            }
            
            boolean isDuplicate = baseMapper.selectCount(duplicateCheckWrapper) > 0;
            String finalFileName = originalFilename;
            
            if (isDuplicate) {
                finalFileName = generateUniqueFileName(originalFilename, userId, parentId);
            }

            // 创建目录
            String datePath = LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            String uploadDir = uploadPath + "/" + datePath;
            File dir = new File(uploadDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            // 保存文件
            String fileName = IdUtil.simpleUUID() + "_" + finalFileName;
            String filePath = "/" + datePath + "/" + fileName;
            File dest = new File(uploadDir, fileName);
            file.transferTo(dest);

            // 保存文件信息到数据库
            Files newFile = new Files();
            newFile.setUserId(userId);
            newFile.setParentId(parentId);
            newFile.setFileName(finalFileName);
            newFile.setFileType(fileType);
            newFile.setFileSize(fileSize);
            newFile.setFilePath(filePath);
            newFile.setIsDirectory(0);
            newFile.setFileMd5(fileMd5);
            newFile.setStatus(1);
            
            save(newFile);
            
            // 更新用户存储空间
            Result<Void> updateResult = userFeignClient.updateStorageUsed(userId, fileSize);
            if (updateResult == null || !updateResult.isSuccess()) { 
                throw new RuntimeException("更新用户存储空间失败");
            }

            FileVO fileVO = new FileVO();
            BeanUtils.copyProperties(newFile, fileVO);
            fileVO.setIsDirectory(false);
            return fileVO;
        } catch (IOException e) {
            log.error("Error uploading file for user {}: {}", userId, e.getMessage(), e);
            throw new RuntimeException("文件上传失败", e);
        }
    }

    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_FILES_PREFIX, key = "#result.id")
    public FileVO createFolder(FileDTO fileDTO) {
        // 检查同名文件夹
        LambdaQueryWrapper<Files> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Files::getUserId, fileDTO.getUserId())
                .eq(Files::getFileName, fileDTO.getFileName())
                .eq(Files::getIsDirectory, 1)
                .eq(Files::getStatus, 1);
        
        if (fileDTO.getParentId() == null) {
            queryWrapper.isNull(Files::getParentId);
        } else {
            queryWrapper.eq(Files::getParentId, fileDTO.getParentId());
        }

        if (baseMapper.selectCount(queryWrapper) > 0) {
            throw new RuntimeException("已存在同名文件夹");
        }

        Files folder = new Files();
        folder.setUserId(fileDTO.getUserId());
        folder.setParentId(fileDTO.getParentId());
        folder.setFileName(fileDTO.getFileName());
        folder.setIsDirectory(1);
        folder.setStatus(1);
        folder.setFileSize(0L);

        save(folder);

        FileVO fileVO = new FileVO();
        BeanUtils.copyProperties(folder, fileVO);
        fileVO.setIsDirectory(true);
        return fileVO;
    }

    @Override
    @DataCache(prefix = CACHE_USER_FILES_PREFIX, 
               key = "#userId + ':' + #parentId", 
               expireTime = CacheConstants.TTL_SECONDS_DEFAULT)
    public List<FileVO> listFiles(String userId, String parentId) {
        if ("root".equals(parentId)) {
            parentId = null;
        }
        
        LambdaQueryWrapper<Files> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Files::getUserId, userId);
        
        if (parentId == null) {
            queryWrapper.isNull(Files::getParentId);
        } else {
            queryWrapper.eq(Files::getParentId, parentId);
        }
        queryWrapper.eq(Files::getStatus, 1);
        
        List<Files> files = baseMapper.selectList(queryWrapper);

        return files.stream().map(fileData -> {
            FileVO fileVO = new FileVO();
            BeanUtils.copyProperties(fileData, fileVO);
            fileVO.setIsDirectory(fileData.getIsDirectory() == 1);
            return fileVO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_FILES_PREFIX, key = "#fileDTO.id")
    public FileVO renameFile(FileDTO fileDTO) {
        Files file = baseMapper.selectById(fileDTO.getId());
        if (file == null || file.getStatus() != 1) {
            throw new RuntimeException("文件或文件夹不存在");
        }
        
        if (!file.getUserId().equals(fileDTO.getUserId())) {
            throw new RuntimeException("无权限操作");
        }

        // 检查同名文件
        LambdaQueryWrapper<Files> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Files::getUserId, fileDTO.getUserId())
                .eq(Files::getFileName, fileDTO.getFileName())
                .eq(Files::getStatus, 1)
                .ne(Files::getId, fileDTO.getId());
        
        if (file.getParentId() == null) {
            queryWrapper.isNull(Files::getParentId);
        } else {
            queryWrapper.eq(Files::getParentId, file.getParentId());
        }
        
        if (baseMapper.selectCount(queryWrapper) > 0) {
            throw new RuntimeException("目标位置已存在同名文件或文件夹");
        }

        file.setFileName(fileDTO.getFileName());
        updateById(file);

        FileVO fileVO = new FileVO();
        BeanUtils.copyProperties(file, fileVO);
        fileVO.setIsDirectory(file.getIsDirectory() == 1);
        return fileVO;
    }

    @Override
    @Transactional
    @DataCacheEvict(prefix = CACHE_FILES_PREFIX, key = "#fileId")
    public boolean moveFile(String fileId, String targetId, String userId) {
        Files fileToMove = baseMapper.selectById(fileId);
        if (fileToMove == null || fileToMove.getStatus() != 1) {
            throw new RuntimeException("要移动的文件或文件夹不存在");
        }
        
        if (!fileToMove.getUserId().equals(userId)) {
            throw new RuntimeException("无权限操作");
        }
        
        String targetParentId = "root".equals(targetId) ? null : targetId;
        
        // 检查目标文件夹
        if (targetParentId != null) {
            Files targetFolder = baseMapper.selectById(targetParentId);
            if (targetFolder == null || targetFolder.getStatus() != 1 || targetFolder.getIsDirectory() != 1) {
                throw new RuntimeException("目标文件夹不存在");
            }
            if (!targetFolder.getUserId().equals(userId)) {
                throw new RuntimeException("无权限移动到目标文件夹");
            }
        }

        // 检查同名文件
        LambdaQueryWrapper<Files> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Files::getUserId, userId)
                .eq(Files::getFileName, fileToMove.getFileName())
                .eq(Files::getStatus, 1)
                .ne(Files::getId, fileId);
        
        if (targetParentId == null) {
            queryWrapper.isNull(Files::getParentId);
        } else {
            queryWrapper.eq(Files::getParentId, targetParentId);
        }
        
        if (baseMapper.selectCount(queryWrapper) > 0) {
            throw new RuntimeException("目标文件夹已存在同名文件或文件夹");
        }

        fileToMove.setParentId(targetParentId);
        return updateById(fileToMove);
    }

    /**
     * 生成唯一文件名
     */
    private String generateUniqueFileName(String originalFilename, String userId, String parentId) {
        String baseName = getFileNameWithoutExtension(originalFilename);
        String extension = getFileExtension(originalFilename);
        
        LambdaQueryWrapper<Files> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Files::getUserId, userId)
                .eq(Files::getStatus, 1);
        
        if (parentId == null) {
            queryWrapper.isNull(Files::getParentId);
        } else {
            queryWrapper.eq(Files::getParentId, parentId);
        }
        
        String newFilename;
        int count = 1;
        
        do {
            newFilename = baseName + "(" + count + ")" + extension;
            queryWrapper.eq(Files::getFileName, newFilename);
            count++;
        } while (baseMapper.selectCount(queryWrapper) > 0);
        
        return newFilename;
    }

    private String getFileNameWithoutExtension(String filename) {
        int lastDotIndex = filename.lastIndexOf('.');
        return lastDotIndex > 0 ? filename.substring(0, lastDotIndex) : filename;
    }

    private String getFileExtension(String filename) {
        int lastDotIndex = filename.lastIndexOf('.');
        return lastDotIndex > 0 ? filename.substring(lastDotIndex) : "";
    }
}
